package lx;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class demo5 {
    /*
        制造假数据：
            获取姓氏：https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0
            获取男生名字：http://www.haoming8.cn/baobao/10881.html
            获取女生名字：http://www.haoming8.cn/baobao/7641.html
       */
    public static void main(String[] args) throws IOException {
        //1.定义变量记录网址
        String familyNameNet = "https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
        String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
        String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";

        //2.爬取数据,把网址上所有的数据拼接成一个字符串
        String familyNameStr = webCrawler(familyNameNet);
        String boyNameStr = webCrawler(boyNameNet);
        String girlNameStr = webCrawler(girlNameNet);
        //3.通过正则表达式，把其中符合要求的数据获取出来
        /*正则表达式
        赵钱孙李，周吴郑王。

        分析姓氏：
         4个任意字符 后面不是逗号就是句号  (.){4}(，|。)
             但是我们要的是字符不是标点符号 所以我们要分组表达
             (.){4}把前面4个任意字符看成一组 然后用?=匹配后面不是逗号就是句号
             (.){4}(?=，|。)---  ？理解为匹配前面的字符，=表示匹配后面不是逗号就是句号，但是在获取的时候只看前面的
         */


        ArrayList<String> familyNameTempList = getData(familyNameStr, "((.){4})(?=，|。)");
        /*
        分析男生名字：
        昌瑞、胜游、文永。 由2个汉字组成的字符 汉字的正则表达式：[\\u4E00-\\u9FA5]，二个组成的([\\u4E00-\\u9FA5]){2}
        并且名字和名字之间是、或者。结尾   ([\\u4E00-\\u9FA5]){2}(?=、|。)
        ?= 这个是匹配前面的字符，=表示匹配后面不是瞪号就是句号，但是在获取的时候只看前面的
         */
        ArrayList<String> boyNameTempList = getData(boyNameStr, "([\\u4E00-\\u9FA5]{2})(?=、|。)");
        /*
        分析女生名字：
        错的例子：
            彤舞 芊静 艾丝 惠蕙 语月  由2个汉字组成的字符--> ([\\u4E00-\\u9FA5]){2}
             并且名字和名字之间是空格结尾的     ([\\u4E00-\\u9FA5]){2}(?=\\s)
             ?= 这个是匹配前面的字符，=表示匹 配后面是空格，但是在获取的时候只看前面的
             正确的例子：
             彤舞 芊静 艾丝 惠蕙 语月  我们把他当一整行处理
             就是彤舞 芊静 艾丝 惠蕙 语月是有二个汉字组成并且汉字和汉字之间有空格，
             我们可以把二个汉字和一个空格看成一个整体 ---->(([\\u4E00-\\u9FA5] ){2})
             出现了四次还剩一个语月我们就写成[\\u4E00-\\u9FA5])即可
             完整的正则表达式：(([\\u4E00-\\u9FA5]){2} ){4}(([\\u4E00-\\u9FA5])){2}
             或者(.. ){4}(.. )
         */
        ArrayList<String> girlNameTempList = getData(girlNameStr, "(([\\u4E00-\\u9FA5]){2} ){4}(([\\u4E00-\\u9FA5])){2}");


     /*   ArrayList<String> familyNameTempList = getData(familyNameStr,"(.{4})(，|。)");
        ArrayList<String> boyNameTempList = getData(boyNameStr,"([\\u4E00-\\u9FA5]{2})(、|。)");
        ArrayList<String> girlNameTempList = getData(girlNameStr,"(.. ){4}..");*/



        //4.处理数据
        //familyNameTempList（姓氏）
        //处理方案：把每一个姓氏拆开并添加到一个新的集合当中
        ArrayList<String> familyNameList = new ArrayList<>();
        for (String str : familyNameTempList) {
            //这里的str表示一个网站中的一组姓氏 如:赵钱孙李
            //还要得到str里的每一个姓氏，并添加到familyNameList 集合当中
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                familyNameList.add(c + "");
            }
        }
        //boyNameTempList（男生的名字）
        //处理方案：去除其中的重复元素(因为boyNameTempList集合有很多重复的名字）
        ArrayList<String> boyNameList = new ArrayList<>();
        for (String str : boyNameTempList) {
            //这里的str表示一个网站中的一个名字 如:昌瑞、胜游、文永。
            if (!boyNameList.contains(str)) {
                boyNameList.add(str);
            }
        }
        //girlNameTempList（女生的名字）
        //处理方案：把里面的每一个元素用空格进行切割，得到每一个女生的名字
        //彤舞 芊静 艾丝 惠蕙 语月
        ArrayList<String> girlNameList = new ArrayList<>();

        for (String str : girlNameTempList) {
            //这里的str表示一个网站中的一组女生名字 如:彤舞 芊静 艾丝 惠蕙 语月
            String[] arr = str.split(" ");
            //0索引是第一个名字 1索引第二个名字，以此类推，
            //获取arr数组的每一个元素，并添加到集合当中
            for (String s : arr) {
                girlNameList.add(s);
            }
        }
        //5.生成数据
        //姓名（唯一）-性别-年龄
        ArrayList<String> list = getInfos(familyNameList, boyNameList, girlNameList, 70, 50);
        Collections.shuffle(list);

        //6.写出数据
        BufferedWriter bw = new BufferedWriter(new FileWriter("names.txt"));
        for (String str : list) {
            bw.write(str);
            bw.newLine();
        }
        bw.close();
    }

    /*
     * 作用：
     *      获取男生和女生的信息：张三-男-23
     *
     * 形参：
     *      参数一：装着姓氏的集合
     *      参数二：装着男生名字的集合
     *      参数三：装着女生名字的集合
     *      参数四：男生的个数
     *      参数五：女生的个数
     * */
    private static ArrayList<String> getInfos(ArrayList<String> familyNameList, ArrayList<String> boyNameList, ArrayList<String> girlNameList, int boyCount, int girlCount) {
        //1.生成男生不重复的名字
        HashSet<String> boyhs = new HashSet<>();
        while (true) {
            if (boyhs.size() == boyCount) {
                break;
            }
            //随机姓氏
            Collections.shuffle(familyNameList);
            //随机男生名字
            Collections.shuffle(boyNameList);
            //拿着0索引的姓氏和0索引的男生名字拼接放入boyhs集合当中
            boyhs.add(familyNameList.get(0) + boyNameList.get(0));
        }
        //2.生成女生不重复的名字
        HashSet<String> girlhs = new HashSet<>();
        while (true) {
            if (girlhs.size() == boyCount) {
                break;
            }
            //随机姓氏
            Collections.shuffle(familyNameList);
            //随机女生名字
            Collections.shuffle(girlNameList);
            //拿着0索引的姓氏和0索引的女生名字拼接放入girlhs集合当中
            girlhs.add(familyNameList.get(0) + girlNameList.get(0));
        }
        //3.生成男生的信息并添加到集合当中
        //张三-男-23
        ArrayList<String> List = new ArrayList<>();
        //获取年龄，我指定男生的年龄范围是18-27
        Random r = new Random();
        for (String boyName : boyhs) {
            //boyName依次表示每一个男生的名字
            int age = r.nextInt(10) + 18;

            List.add(boyName + "-男-" + age);
        }
        //4.生成女生的信息并添加到集合当中
        //获取年龄，我指定女生的年龄范围是18-25
        for (String girlName : girlhs) {
            //girlName依次表示每一个女生的名字
            int age = r.nextInt(8) + 18;

            List.add(girlName + "-女-" + age);
        }
        //返回集合

        return List;

    }

    /*
     * 作用：根据正则表达式获取字符串中的数据
     * 参数一：
     *       完整的字符串
     * 参数二：
     *       正则表达式
     * 返回值：
     *       真正想要的数据
     *
     * */
    private static ArrayList<String> getData(String str, String regex) {
        //1.创建集合存储数据
        ArrayList<String> list = new ArrayList<>();
        //2.按照正则表达式获取数据
        Pattern pattern = Pattern.compile(regex);
        //3.获取文本匹配器的对象m去读取str，利用规则p找小串
        Matcher m = pattern.matcher(str);
        //4.循环读取str字符串，找到符合规则的就截取下来并存入集合当中
        while (m.find()) {

            String group = m.group();

            list.add(group);

        }
        return list;


    }

    /*
     * 作用：
     *   从网络中爬取数据，把数据拼接成字符串返回
     * 形参：
     *   网址
     * 返回值：
     *   爬取到的所有数据
     * */
    private static String webCrawler(String net) throws IOException {

        //1.创建URL对象 关联网站
        URL url = new URL(net);
        //2.连接网站
        URLConnection coon = url.openConnection();
        //读取网站的信息拼接成字符串
        StringBuilder sb = new StringBuilder();
        //3.利用转换流读取网站数据
        //细节： 因为读取网站数据是中文，所以需要转换流
        //且coon.getInputStream()只能使用字节流
        InputStreamReader isr = new InputStreamReader(coon.getInputStream());
        int len;
        while ((len = isr.read()) != -1) {
            sb.append((char) len);
        }
        //4.释放资源
        isr.close();
        //5.把读取到的数据返回
        return sb.toString();
    }

}
